home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-wos-src / vlink / targets.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  26KB  |  906 lines

  1. /* $VER: vlink targets.c V0.6c (05.02.99)
  2.  *
  3.  * This file is part of vlink, a portable linker for multiple
  4.  * object formats.
  5.  * Copyright (c) 1997-99  Frank Wille
  6.  *
  7.  * vlink is freeware and part of the portable and retargetable ANSI C
  8.  * compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
  9.  * vlink may be freely redistributed as long as no modifications are
  10.  * made and nothing is charged for it. Non-commercial usage is allowed
  11.  * without any restrictions.
  12.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  13.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  14.  *
  15.  *
  16.  * v0.6c (05.02.99) phx
  17.  *       ctors/dtors sections always start with 0xffffffff to provide
  18.  *       compatibility with most file formats (e.g. ELF).
  19.  * v0.6a (19.12.98) phx
  20.  *       Support for little endian object file formats.
  21.  *       readsection()/writesection() obey current endianess of linking
  22.  *       process.
  23.  *       make_priptr_objects() updates linker symbols during add_da-
  24.  *       ta_section().
  25.  * v0.6  (24.10.98) phx
  26.  *       find_lnksec() finds a LinkedSection by its name and/or type
  27.  *       (needed for ELF small data support).
  28.  *       New target elf32powerup, which supports the PPC coprocessor
  29.  *       boards from Phase5.
  30.  * v0.5e (05.10.98) phx
  31.  *       new_priptr(), add_priptrs(), make_priptr_objects(). Support for
  32.  *       artificial sections and objects, containing longwords sorted by
  33.  *       priority. These sections are automatically terminated by a NULL
  34.  *       pointer entry. Currently only used by ados-target for constructor
  35.  *       and destructor function pointer lists (__ctors, __dtors).
  36.  * v0.5c (08.07.98) phx
  37.  *       art_objunit() creates an artificial ObjectUnit + LinkFile.
  38.  * v0.5  (27.06.98) phx
  39.  *       addlnksymbol(), findlnksymbol() for target-specific linker
  40.  *       symbol support.
  41.  *       smalldata_section() returns a pointer to the first section,
  42.  *       which is referenced base relative.
  43.  * v0.3  (17.04.98) phx
  44.  *       addlocsymbol() allows multiple defintions of local
  45.  *       symbols with the same name.
  46.  *       addreloc() adds another relocation to a section.
  47.  *       relocsize() determines size in bytes of a relocation type.
  48.  *       addxref() requires the addend as additional argument.
  49.  *       ar-support functions for library archives.
  50.  * v0.1  (27.02.98) phx
  51.  *       First version that seems to link AmigaOS ADOS and EHF
  52.  *       objects and libraries. Many common features, like linking
  53.  *       sections together which have relative references, are
  54.  *       still missing. Also, PowerPC-ELF32 support is about to come.
  55.  * v0.0  (05.08.97) phx
  56.  *       File created.
  57.  */
  58.  
  59.  
  60. #define TARGETS_C
  61. #include "vlink.h"
  62.  
  63.  
  64. unsigned long findsecbase(struct GlobalVars *,char *);
  65. struct Symbol *findsymbol(struct GlobalVars *,char *name);
  66. struct Symbol *addsymbol(struct GlobalVars *,struct Section *,char *,
  67.                          uint32,uint8,uint8,uint8,uint8,uint32);
  68. void addlocsymbol(struct GlobalVars *,struct Section *,char *,uint32,
  69.                   uint8,uint8,uint8,uint32);
  70. void addglobsym(struct GlobalVars *,struct Symbol *);
  71. struct Symbol *addlnksymbol(struct FFFuncs *,struct Section *,char *,
  72.                             uint32,uint8,uint8,uint8,uint8,uint32);
  73. struct Symbol *findlnksymbol(struct FFFuncs *,char *);
  74. void addreloc(struct Section *,struct Section *,uint32,uint32,uint8,int32);
  75. void addxref(struct GlobalVars *,struct Section *,char *,uint32,uint8,
  76.              uint8,int32);
  77. int32 readsection(struct GlobalVars *,uint8 *,uint8);
  78. void writesection(struct GlobalVars *,uint8 *,uint8,uint32);
  79. uint8 relocsize(uint8);
  80. struct Section *create_section(struct ObjectUnit *,char *,uint8 *,
  81.                                unsigned long);
  82. struct Section *find_sect_type(struct ObjectUnit *,uint8,uint8);
  83. struct Section *find_sect_id(struct ObjectUnit *,uint32);
  84. struct LinkedSection *find_lnksec(struct GlobalVars *,char *,uint8,
  85.                                   uint8,uint8);
  86. struct LinkedSection *smalldata_section(struct GlobalVars *);
  87. void add_objunit(struct GlobalVars *,struct ObjectUnit *,bool);
  88. struct ObjectUnit *create_objunit(struct LinkFile *,char *);
  89. struct ObjectUnit *art_objunit(char *,uint8 *,unsigned long,uint8);
  90. void new_priptr(struct ObjectUnit *,char *,char *,int,char *,uint32);
  91. void add_priptrs(struct GlobalVars *,struct ObjectUnit *);
  92. void make_priptr_objects(struct GlobalVars *);
  93. bool ar_init(struct ar_info *,char *,unsigned long,char *);
  94. bool ar_extract(struct ar_info *);
  95.  
  96. static struct Section *getsecptr(struct list *,uint32);
  97. static struct Section *add_data_section(struct GlobalVars *,
  98.                                         struct ObjectUnit *,char *,uint8 *,
  99.                                         unsigned long);
  100.  
  101.  
  102. struct FFFuncs *fff[] = {
  103. #ifdef ADOS
  104.   &fff_amigaos,
  105. #endif
  106. #ifdef EHF
  107.   &fff_ehf,
  108. #endif
  109. #ifdef ELF32_PPC_BE
  110.   &fff_elf32ppcbe,
  111. #endif
  112. #ifdef ELF32_POWERUP
  113.   &fff_elf32powerup,
  114. #endif
  115.   NULL
  116. };
  117.  
  118. const char *sym_type[] = { "undef","abs","reloc","common" };
  119. const char *sym_info[] = { ""," object"," function"," section"," file" };
  120. const char *sym_bind[] = { "","local ","global ","weak " };
  121.  
  122.  
  123.  
  124. unsigned long findsecbase(struct GlobalVars *gv,char *name)
  125. /* scan the secbases list for a base address definition */
  126. {
  127.   struct SecBase *sb = gv->secbases;
  128.  
  129.   while (sb) {
  130.     if (!strcmp(name,sb->name))
  131.       return (sb->base);
  132.     sb = sb->next;
  133.   }
  134. }
  135.  
  136.  
  137. struct Symbol *findsymbol(struct GlobalVars *gv,char *name)
  138. /* return pointer to Symbol, if present */
  139. {
  140.   struct Symbol *sym = gv->symbols[elf_hash(name)%SYMHTABSIZE];
  141.  
  142.   while (sym) {
  143.     if (!strcmp(name,sym->name))
  144.       return (sym);  /* symbol found! */
  145.     sym = sym->glob_chain;
  146.   }
  147.   return (NULL);
  148. }
  149.  
  150.  
  151. struct Symbol *addsymbol(struct GlobalVars *gv,struct Section *s,char *name,
  152.                          uint32 val,uint8 type,uint8 flags,uint8 info,
  153.                          uint8 bind,uint32 size)
  154. /* Define a new symbol. If defined twice in the same object unit, then */
  155. /* return a pointer to its first definition. Defining the symbol twice */
  156. /* globally, is only allowed in different object units of a library. */
  157. {
  158.   struct Symbol *sym;
  159.   struct ObjectUnit *ou = s->obj;
  160.   struct Symbol **chain = &s->obj->objsyms[elf_hash(name)%OBJSYMHTABSIZE];
  161.  
  162.   while (sym = *chain) {
  163.     if (!strcmp(name,sym->name))
  164.       return (sym);  /* symbol already defined - don't define it twice */
  165.       /* The target-specific routines have to handle this case. */
  166.     chain = &sym->obj_chain;
  167.   }
  168.  
  169.   *chain = sym = alloc(sizeof(struct Symbol));
  170.   sym->glob_chain = sym->obj_chain = NULL;
  171.   sym->name = name;
  172.   sym->value = val;
  173.   sym->relsect = s;
  174.   sym->type = type;
  175.   sym->flags = flags;
  176.   sym->info = info;
  177.   sym->bind = bind;
  178.   sym->size = size;
  179.  
  180.   if (bind==SYMB_GLOBAL || bind==SYMB_WEAK)
  181.     addglobsym(gv,sym);
  182.  
  183.   return (NULL);  /* ok, new symbol was created */
  184. }
  185.  
  186.  
  187. void addlocsymbol(struct GlobalVars *gv,struct Section *s,char *name,
  188.                   uint32 val,uint8 type,uint8 flags,uint8 info,uint32 size)
  189. /* Define a new local symbol. Local symbols are allowed to be */
  190. /* multiply defined. */
  191. {
  192.   struct Symbol *sym;
  193.   struct Symbol **chain = &s->obj->objsyms[elf_hash(name)%OBJSYMHTABSIZE];
  194.  
  195.   while (sym = *chain)
  196.     chain = &sym->obj_chain;
  197.   *chain = sym = alloc(sizeof(struct Symbol));
  198.   sym->glob_chain = sym->obj_chain = NULL;
  199.   sym->name = name;
  200.   sym->value = val;
  201.   sym->relsect = s;
  202.   sym->type = type;
  203.   sym->flags = flags;
  204.   sym->info = info;
  205.   sym->bind = SYMB_LOCAL;
  206.   sym->size = size;
  207. }
  208.  
  209.  
  210. void addglobsym(struct GlobalVars *gv,struct Symbol *newsym)
  211. /* insert symbol into global symbol hash table */
  212. {
  213.   struct Symbol **chain = &gv->symbols[elf_hash(newsym->name)%SYMHTABSIZE];
  214.   struct Symbol *sym;
  215.   struct ObjectUnit *newou = newsym->relsect->obj;
  216.  
  217.   while (sym = *chain) {
  218.     if (!strcmp(newsym->name,sym->name)) {
  219.       if (sym->bind == SYMB_GLOBAL) {
  220.         /* symbol already defined with global binding */
  221.         if (newsym->bind==SYMB_GLOBAL && newou->lnkfile->type<ID_LIBBASE) {
  222.           if (newsym->type==SYM_COMMON && sym->type==SYM_COMMON) {
  223.             if (newsym->size > sym->size) {
  224.               /* replace by common symbol with bigger size */
  225.               newsym->glob_chain = sym->glob_chain;
  226.               sym->glob_chain = NULL;
  227.               break;
  228.             }
  229.           }
  230.           else
  231.             /* Global symbol "x" is already defined in... */
  232.             error(19,newou->lnkfile->pathname,newsym->name,newou->objname,
  233.                   sym->relsect->obj->lnkfile->pathname,
  234.                   sym->relsect->obj->objname);
  235.         }
  236.         return;  /* don't replace global symbols */
  237.       }
  238.  
  239.       else {
  240.         if (newsym->bind == SYMB_WEAK)
  241.           return;  /* don't replace weak by weak */
  242.         /* replace weak symbol */
  243.         newsym->glob_chain = sym->glob_chain;
  244.         sym->glob_chain = NULL;
  245.         break;
  246.       }
  247.     }
  248.     chain = &sym->glob_chain;
  249.   }
  250.  
  251.   *chain = newsym;
  252.   if (trace_sym_access(gv,newsym->name))
  253.     fprintf(stderr,"Symbol %s defined in section %s in %s\n",
  254.             newsym->name,newsym->relsect->name,getobjname(newou));
  255. }
  256.  
  257.  
  258. struct Symbol *addlnksymbol(struct FFFuncs *fffptr,struct Section *s,
  259.                             char *name,uint32 val,uint8 type,uint8 flags,
  260.                             uint8 info,uint8 bind,uint32 size)
  261. /* Define a new, target-specific, linker symbol. */
  262. {
  263.   struct Symbol *sym;
  264.   struct Symbol **chain;
  265.  
  266.   if (fffptr->lnksyms == NULL)
  267.     fffptr->lnksyms = alloc_hashtable(LNKSYMHTABSIZE);
  268.   chain = &fffptr->lnksyms[elf_hash(name)%LNKSYMHTABSIZE];
  269.  
  270.   while (sym = *chain)
  271.     chain = &sym->obj_chain;
  272.   *chain = sym = alloc(sizeof(struct Symbol));
  273.   sym->glob_chain = sym->obj_chain = NULL;
  274.   sym->name = name;
  275.   sym->value = val;
  276.   sym->relsect = s;
  277.   sym->type = type;
  278.   sym->flags = flags;
  279.   sym->info = info;
  280.   sym->bind = bind;
  281.   sym->size = size;
  282.   return (sym);
  283. }
  284.  
  285.  
  286. struct Symbol *findlnksymbol(struct FFFuncs *fffptr,char *name)
  287. /* return pointer to Symbol, if present */
  288. {
  289.   struct Symbol *sym;
  290.  
  291.   if (fffptr->lnksyms) {
  292.     sym = fffptr->lnksyms[elf_hash(name)%LNKSYMHTABSIZE];
  293.     while (sym) {
  294.       if (!strcmp(name,sym->name))
  295.         return (sym);  /* symbol found! */
  296.       sym = sym->obj_chain;
  297.     }
  298.   }
  299.   return (NULL);
  300. }
  301.  
  302.  
  303. void addreloc(struct Section *cs,struct Section *rs,uint32 id,
  304.               uint32 offset,uint8 rtype,int32 addend)
  305. /* add a relocation to the specified section */
  306. {
  307.   struct Reloc *r = alloc(sizeof(struct Reloc));
  308.  
  309.   if (rs)
  310.     r->relocsect.ptr = rs;
  311.   else
  312.     r->relocsect.id = id;
  313.   r->offset = (unsigned long)offset;
  314.   r->addend = addend;
  315.   r->type = rtype;
  316.   addtail(&cs->relocs,&r->n);  /* add to current section's Reloc list */
  317. }
  318.  
  319.  
  320. void addxref(struct GlobalVars *gv,struct Section *s,char *name,
  321.              uint32 offset,uint8 rtype,uint8 size,int32 addend)
  322. /* add external symbol reference */
  323. {
  324.   struct XReference *xref = alloczero(sizeof(struct XReference));
  325.  
  326.   xref->name = name;
  327.   xref->offset = (unsigned long)offset;
  328.   xref->type = rtype;
  329.   xref->size = size;
  330.   xref->addend = addend;
  331.   addtail(&s->xrefs,&xref->n);
  332.   if (trace_sym_access(gv,name))
  333.     fprintf(stderr,"Symbol %s referenced in %s\n",name,getobjname(s->obj));
  334. }
  335.  
  336.  
  337. int32 readsection(struct GlobalVars *gv,uint8 *p,uint8 rtype)
  338. /* Read 8-, 16- or 32-bit word from a section. The data-width is */
  339. /* determined from the relocation type rtype. */
  340. {
  341.   int32 v;
  342.   char be = gv->big_endian;
  343.  
  344.   switch (rtype) {
  345.  
  346.     case R_REL8:
  347.     case R_BASEREL8:
  348.       v = (int32)*p;
  349.       break;
  350.  
  351.     case R_ADDR14:  /* PowerPC */
  352.     case R_ADDR14_BRTAKEN:
  353.     case R_ADDR14_BRNTAKEN:
  354.     case R_REL14:
  355.     case R_REL14_BRTAKEN:
  356.     case R_REL14_BRNTAKEN:
  357.       v = (int32)read16(be,p) & 0xfffffffc;
  358.       break;
  359.  
  360.     case R_ADDR16:
  361.     case R_ADDR16_LO:
  362.     case R_ADDR16_HI:
  363.     case R_ADDR16_HA:
  364.     case R_REL16:
  365.     case R_BASEREL16:
  366.       v = (int32)read16(be,p);
  367.       break;
  368.  
  369.     case R_ADDR26:  /* PowerPC */
  370.     case R_REL26:
  371.     case R_BASEREL26:
  372.       v = (int32)(read32(be,p) & 0x3fffffc);
  373.       if (v >= 0x2000000)
  374.         v = -v;
  375.       break;
  376.  
  377.     default:
  378.       v = (int32)read32(be,p);
  379.       break;
  380.   }
  381.   return (v);
  382. }
  383.  
  384.  
  385. void writesection(struct GlobalVars *gv,uint8 *p,uint8 rtype,uint32 x)
  386. /* Write a 8-, 16- or 32-bit word into a section. The data-width is */
  387. /* determined from the relocation type rtype. */
  388. {
  389.   char be = gv->big_endian;
  390.  
  391.   switch (rtype) {
  392.  
  393.     case R_REL8:
  394.     case R_BASEREL8:
  395.       *p = (uint8)x;
  396.       break;
  397.  
  398.     case R_ADDR14:  /* PowerPC */
  399.     case R_ADDR14_BRTAKEN:
  400.     case R_ADDR14_BRNTAKEN:
  401.     case R_REL14:
  402.     case R_REL14_BRTAKEN:
  403.     case R_REL14_BRNTAKEN:
  404.       write16(be,p,(read16(be,p) & 3) | (uint16)(x & 0xfffc));
  405.       break;
  406.  
  407.     case R_ADDR16:
  408.     case R_ADDR16_LO:
  409.     case R_ADDR16_HI:
  410.     case R_ADDR16_HA:
  411.     case R_REL16:
  412.     case R_BASEREL16:
  413.       write16(be,p,(uint16)(x & 0xffff));
  414.       break;
  415.  
  416.     case R_ADDR26:  /* PowerPC */
  417.     case R_REL26:
  418.     case R_BASEREL26:
  419.       write32(be,p,(read32(be,p) & 0xfc000000) | (x & 0x3ffffff));
  420.       break;
  421.  
  422.     default:
  423.       write32(be,p,x);
  424.       break;
  425.   }
  426. }
  427.  
  428.  
  429. uint8 relocsize(uint8 rtype)
  430. /* determine size of relocation in bytes for the specified reloc type */
  431. {
  432.   switch (rtype) {
  433.  
  434.     case R_REL8:
  435.     case R_BASEREL8:
  436.       return (1);
  437.  
  438.     case R_ADDR14:
  439.     case R_ADDR14_BRTAKEN:
  440.     case R_ADDR14_BRNTAKEN:
  441.     case R_REL14:
  442.     case R_REL14_BRTAKEN:
  443.     case R_REL14_BRNTAKEN:
  444.     case R_ADDR16:
  445.     case R_ADDR16_LO:
  446.     case R_ADDR16_HI:
  447.     case R_ADDR16_HA:
  448.     case R_REL16:
  449.     case R_BASEREL16:
  450.       return (2);
  451.  
  452.     case R_ADDR26:
  453.     case R_REL26:
  454.     case R_BASEREL26:
  455.       return (3);
  456.   }
  457.   return (4);
  458. }
  459.  
  460.  
  461. struct Section *create_section(struct ObjectUnit *ou,char *name,
  462.                                uint8 *data,unsigned long size)
  463. /* creates and initializes a Section node */
  464. {
  465.   static char *noname = "";
  466.   static uint32 idcnt = 0;
  467.   struct Section *s = alloczero(sizeof(struct Section));
  468.  
  469.   if (name)
  470.     s->name = name;
  471.   else
  472.     s->name = noname;
  473.   s->data = data;
  474.   s->size = size;
  475.   s->obj = ou;
  476.   s->id = idcnt++;
  477.   initlist(&s->relocs);  /* empty relocation list */
  478.   initlist(&s->xrefs);   /* empty external references list */
  479.   return (s);
  480. }
  481.  
  482.  
  483. struct Section *find_sect_type(struct ObjectUnit *ou,uint8 type,uint8 prot)
  484. /* find a section in current object unit with approp. type and protection */
  485. {
  486.   struct Section *sec = (struct Section *)ou->sections.first;
  487.   struct Section *nextsec;
  488.  
  489.   while (nextsec = (struct Section *)sec->n.next) {
  490.     if (sec->type==type && (sec->protection&prot)==prot)
  491.       return (sec);
  492.     sec = nextsec;
  493.   }
  494.   return (NULL);
  495. }
  496.  
  497.  
  498. struct Section *find_sect_id(struct ObjectUnit *ou,uint32 id)
  499. /* find a section by its identification value */
  500. {
  501.   struct Section *sec = (struct Section *)ou->sections.first;
  502.   struct Section *nextsec;
  503.  
  504.   while (nextsec = (struct Section *)sec->n.next) {
  505.     if (sec->id == id)
  506.       return (sec);
  507.     sec = nextsec;
  508.   }
  509.   return (NULL);
  510. }
  511.  
  512.  
  513. struct LinkedSection *find_lnksec(struct GlobalVars *gv,char *name,
  514.                                   uint8 type,uint8 flags,uint8 fmask)
  515. /* Return pointer to the first section which fits the passed */
  516. /* name-, type- and flags-conditions. If a condition is 0, then */
  517. /* it is ignored. If no appropriate section was found, return NULL. */
  518. {
  519.   struct LinkedSection *ls = (struct LinkedSection *)gv->lnksec.first;
  520.   struct LinkedSection *nextls;
  521.  
  522.   while (nextls = (struct LinkedSection *)ls->n.next) {
  523.     bool found = TRUE;
  524.  
  525.     if (name)
  526.       if (strcmp(ls->name,name))
  527.         found = FALSE;
  528.     if (type)
  529.       if (ls->type != type)
  530.         found = FALSE;
  531.     if (fmask)
  532.       if ((ls->flags&fmask) != (flags&fmask))
  533.         found = FALSE;
  534.     if (found)
  535.       return (ls);
  536.     ls = nextls;
  537.   }
  538.   return (NULL);
  539. }
  540.  
  541.  
  542. struct LinkedSection *smalldata_section(struct GlobalVars *gv)
  543. /* Return pointer to first small data LinkedSection. If not existing, */
  544. /* return first data/bss section or the first section. */
  545. {
  546.   struct LinkedSection *ls = (struct LinkedSection *)gv->lnksec.first;
  547.   struct LinkedSection *ldls=NULL,*nextls;
  548.  
  549.   while (nextls = (struct LinkedSection *)ls->n.next) {
  550.     if (ls->type==ST_DATA || ls->type==ST_UDATA && ldls==NULL)
  551.       ldls = ls;
  552.     if (ls->flags & SF_SMALLDATA)  /* first SD section found! */
  553.       return (ls);
  554.     ls = nextls;
  555.   }
  556.   return (ldls?ldls:((struct LinkedSection *)gv->lnksec.first));
  557. }
  558.  
  559.  
  560. void add_objunit(struct GlobalVars *gv,struct ObjectUnit *ou,bool fixrelocs)
  561. /* adds an ObjectUnit to the approriate list */
  562. {
  563.   if (ou) {
  564.     switch (ou->lnkfile->type) {
  565.       case ID_OBJECT:
  566.       case ID_EXECUTABLE:
  567.         addtail(&gv->selobjects,&ou->n);
  568.         add_priptrs(gv,ou);
  569.         break;
  570.       case ID_LIBARCH:
  571.         addtail(&gv->libobjects,&ou->n);
  572.         break;
  573.       case ID_SHAREDOBJ:
  574.         addtail(&gv->sharedobjects,&ou->n);
  575.         break;
  576.       default:
  577.         ierror("add_objunit(): Link File type = %d",
  578.                (int)ou->lnkfile->type);
  579.     }
  580.  
  581.     if (fixrelocs) {  /* convert section index into address */
  582.       struct Section *sec = (struct Section *)ou->sections.first;
  583.       struct Section *nextsec;
  584.  
  585.       while (nextsec = (struct Section *)sec->n.next) {
  586.         struct Reloc *r = (struct Reloc *)sec->relocs.first;
  587.         struct Reloc *nextr;
  588.  
  589.         while (nextr = (struct Reloc *)r->n.next) {
  590.           r->relocsect.ptr = getsecptr(&ou->sections,r->relocsect.id);
  591.           r = nextr;
  592.         }
  593.         sec = nextsec;
  594.       }
  595.     }
  596.   }
  597. }
  598.  
  599.  
  600. static struct Section *getsecptr(struct list *seclist,uint32 index)
  601. /* return pointer to i. section in list */
  602. {
  603.   int i = (int)index;
  604.   struct Section *s = (struct Section *)seclist->first;
  605.   struct Section *nexts;
  606.  
  607.   while (i--) {
  608.     if (s->n.next == NULL)
  609.       ierror("getsecptr(): Not enough sections in list for index=%u",index);
  610.     else
  611.       s = (struct Section *)s->n.next;
  612.   }
  613.   return (s);
  614. }
  615.  
  616.  
  617. struct ObjectUnit *create_objunit(struct LinkFile *lf,char *objname)
  618. /* creates and initializes an ObjectUnit node */
  619. {
  620.   struct ObjectUnit *ou = alloc(sizeof(struct ObjectUnit));
  621.   static char *noname="";
  622.  
  623.   ou->lnkfile = lf;
  624.   if (objname)
  625.     ou->objname = objname;
  626.   else
  627.     ou->objname = noname;
  628.   initlist(&ou->sections);  /* empty section list */
  629.   ou->objsyms = alloc_hashtable(OBJSYMHTABSIZE);
  630.   ou->flags = 0;
  631.   initlist(&ou->pripointers);  /* empty PriPointer list */
  632.   return (ou);
  633. }
  634.  
  635.  
  636. struct ObjectUnit *art_objunit(char *n,uint8 *d,unsigned long len,uint8 fmt)
  637. /* creates and initializes an artificial linker-object */
  638. {
  639.   struct LinkFile *lf = alloczero(sizeof(struct LinkFile));
  640.  
  641.   lf->pathname = lf->filename = lf->objname = n;
  642.   lf->data = d;
  643.   lf->length = len;
  644.   lf->format = fmt;
  645.   lf->type = ID_ARTIFICIAL;
  646.   return (create_objunit(lf,n));
  647. }
  648.  
  649.  
  650. void new_priptr(struct ObjectUnit *ou,char *objname,char *sec,int pri,
  651.                 char *xref,uint32 addend)
  652. /* Inserts a new longword into the object's PriPointers list. */
  653. {
  654.   struct PriPointer *newpp = alloc(sizeof(struct PriPointer));
  655.  
  656.   newpp->objname = objname;
  657.   newpp->secname = sec;
  658.   newpp->priority = pri;
  659.   newpp->xrefname = xref;
  660.   newpp->addend = addend;
  661.   addtail(&ou->pripointers,&newpp->n);
  662. }
  663.  
  664.  
  665. void add_priptrs(struct GlobalVars *gv,struct ObjectUnit *ou)
  666. /* Inserts all PriPointer nodes of an object into the global list. */
  667. /* The node's position depends on 1. object name, 2. section name, */
  668. /* 3. priority. */
  669. {
  670.   struct PriPointer *newpp,*nextpp,*pp;
  671.  
  672.   while (newpp = (struct PriPointer *)remhead(&ou->pripointers)) {
  673.     pp = (struct PriPointer *)gv->pripointers.first;
  674.  
  675.     while (nextpp = (struct PriPointer *)pp->n.next) {
  676.       int c;
  677.  
  678.       if ((c = strcmp(newpp->objname,pp->objname)) > 0)
  679.         break;
  680.       if (!c) {
  681.         if ((c = strcmp(newpp->secname,pp->secname)) > 0)
  682.           break;
  683.         if (!c && newpp->priority < pp->priority)
  684.           break;
  685.       }
  686.       pp = nextpp;
  687.     }
  688.  
  689.     if (pp->n.pred)
  690.       insertbefore(&newpp->n,&pp->n);
  691.     else
  692.       addhead(&gv->pripointers,&newpp->n);  /* first node in list */
  693.   }
  694. }
  695.  
  696.  
  697. void make_priptr_objects(struct GlobalVars *gv)
  698. /* Make artificial objects from PriPointer list entries. */
  699. /* This function usually has to be called *before* linker_resolve(). */
  700. {
  701.   struct PriPointer *pp = (struct PriPointer *)gv->pripointers.first;
  702.   struct PriPointer *nextpp,*firstpp = pp;
  703.   unsigned long len = 0;
  704.   uint32 *data;
  705.   struct ObjectUnit *ou = NULL;
  706.   struct Section *s = NULL;
  707.   char be = gv->big_endian;
  708.  
  709.   while (nextpp = (struct PriPointer *)pp->n.next) {
  710.  
  711.     if (!ou) {
  712.       int scmp = strcmp(pp->objname,firstpp->objname);
  713.  
  714.       if (!scmp) {
  715.         len += sizeof(uint32);
  716.         if (nextpp->n.next) {
  717.           if (strcmp(pp->secname,nextpp->secname))
  718.             /* include -1 word and terminating NULL pointer */
  719.             len += 2*sizeof(uint32);
  720.         }
  721.         else {
  722.           /* include -1 word and terminating NULL pointer */
  723.           len += 2*sizeof(uint32);
  724.           scmp = 1;
  725.           pp = nextpp;
  726.         }
  727.       }
  728.       if (scmp) {
  729.         data = alloczero(len);
  730.         ou = art_objunit(firstpp->objname,(uint8 *)data,len,gv->dest_format);
  731.         nextpp = firstpp;  /* begin with first node of same object again */
  732.         firstpp = pp;
  733.       }
  734.     }
  735.  
  736.     else {
  737.       if (pp != firstpp) {
  738.         /* The standard in most file formats is to start with the */
  739.         /* number of function pointers, or with a -1 */
  740.         if (!s) {
  741.           s = add_data_section(gv,ou,pp->secname,(uint8 *)data,
  742.                                2*sizeof(uint32));
  743.           *data++ = 0xffffffff;
  744.         }
  745.         else if (strcmp(pp->secname,s->name)) {
  746.           s = add_data_section(gv,ou,pp->secname,(uint8 *)(++data),
  747.                                2*sizeof(uint32));
  748.           *data++ = 0xffffffff;
  749.         }
  750.         write32(be,(uint8 *)data,pp->addend);
  751.         ++data;
  752.         if (pp->xrefname)
  753.           addxref(gv,s,pp->xrefname,s->size-sizeof(uint32),R_ADDR32,
  754.                   sizeof(uint32),pp->addend);
  755.         s->size += sizeof(uint32);
  756.       }
  757.       if (pp == firstpp || !nextpp->n.next) {
  758.         ou->lnkfile->type = ID_OBJECT;
  759.         add_objunit(gv,ou,FALSE);
  760.         ou = NULL;
  761.         s = NULL;
  762.         len = 0;
  763.         nextpp = firstpp;  /* loop for next object unit */
  764.       }
  765.     }
  766.  
  767.     pp = nextpp;
  768.   }
  769. }
  770.  
  771.  
  772. static struct Section *add_data_section(struct GlobalVars *gv,
  773.                                         struct ObjectUnit *ou,char *name,
  774.                                         uint8 *data,unsigned long size)
  775. {
  776.   struct Section *s = create_section(ou,name,data,size);
  777.  
  778.   s->type = ST_DATA;
  779.   s->protection = SP_READ | SP_WRITE;
  780.   s->alignment = 2;
  781.   addtail(&ou->sections,&s->n);
  782.  
  783.   /* If the section name starts with '_', define it as a global */
  784.   /* symbol which defines the section's base address. */
  785.   if (*name == '_') {
  786.     struct Symbol *realsym,*lnksym;
  787.  
  788.     if (addsymbol(gv,s,name,0,SYM_RELOC,0,SYMI_OBJECT,SYMB_GLOBAL,0)) {
  789.       error(59,name);  /* Can't define symbol as section label */
  790.     }
  791.     else if (lnksym = findlnksymbol(fff[gv->dest_format],name)) {
  792.       if (realsym = findsymbol(gv,name)) {
  793.         /* update a linker symbol, which has the same name */
  794.         lnksym->value = realsym->value;
  795.         lnksym->relsect = realsym->relsect;
  796.         lnksym->type = realsym->type;
  797.         lnksym->flags = realsym->flags | SYMF_LNKSYM;
  798.         lnksym->info = realsym->info;
  799.         lnksym->bind = realsym->bind;
  800.         lnksym->size = realsym->size;
  801.       }
  802.     }
  803.   }
  804.   return (s);
  805. }
  806.  
  807.  
  808. bool ar_init(struct ar_info *ai,char *p,unsigned long plen,char *name)
  809. /* check for valid archive header and initialize ar_info, if successful */
  810. {
  811.   /* check for "!<arch>\n" id */
  812.   if (plen<sizeof(struct ar_hdr) || strncmp(p,ARMAG,SARMAG))
  813.     return (FALSE);
  814.  
  815.   memset(ai,0,sizeof(struct ar_hdr));
  816.   ai->arname = name;
  817.   ai->next = (struct ar_hdr *)(p+SARMAG);
  818.   ai->arlen = plen - SARMAG;
  819.   return (TRUE);
  820. }
  821.  
  822.  
  823. bool ar_extract(struct ar_info *ai)
  824. /* fill ar_info structure with informations about the next */
  825. /* archive member */
  826. {
  827.   struct ar_hdr *ah;
  828.   uint8 *p;
  829.   bool cont;
  830.   unsigned long size;
  831.  
  832.   do {
  833.     cont = FALSE;
  834.     if (ai->next==NULL || ai->arlen<sizeof(struct ar_hdr))
  835.       return (FALSE);  /* archive ends here */
  836.  
  837.     ah = ai->next;
  838.     p = ((uint8 *)ah) + sizeof(struct ar_hdr);
  839.     ai->arlen -= sizeof(struct ar_hdr);
  840.     ai->name[0] = 0;
  841.     sscanf(ah->ar_size,"%lu",&ai->size);  /* file size */
  842.  
  843.     if (!strncmp(ah->ar_name,"/ ",2) ||             /* GNU symbol table */
  844.         !strncmp(ah->ar_name,"__.SYMDEF ",10))      /* BSD symbol table */
  845.       cont = TRUE;
  846.     if (!strncmp(ah->ar_name,"// ",3)) {            /* GNU long names */
  847.       ai->long_names = p;
  848.       cont = TRUE;
  849.     }
  850.  
  851.     if (ai->long_names && ah->ar_name[0]=='/' &&    /* long name (GNU) */
  852.         (ah->ar_name[1]>='0' && ah->ar_name[1]<='9')) {
  853.       int i,offset;
  854.       char c,*s,*d=ai->name;
  855.  
  856.       sscanf(&ah->ar_name[1],"%d",&offset);  /* name offset */
  857.       s = ai->long_names + offset;
  858.       for (i=0; i<MAXARNAME; i++) {
  859.         c = *s++;
  860.         if (c==0 || c=='/' || c=='\n')
  861.           break;
  862.         *d++ = c;
  863.       }
  864.       *d = 0;
  865.     }
  866.     else if (!strncmp(ah->ar_name,"#1/",3)) {  /* ext. name fmt. #1 (BSD) */
  867.       int d,len;
  868.  
  869.       sscanf(&ah->ar_name[3],"%d",&d);  /* ext.fmt. name length */
  870.       if (d > ai->arlen)
  871.         error(37,ai->arname,ai->name);  /* Malformatted archive member */
  872.       len = (d>MAXARNAME) ? MAXARNAME : d;
  873.       memcpy(ai->name,p,len);
  874.       ai->name[len] = 0;
  875.       if (d & 1)
  876.         ++d;   /* align to even offset */
  877.       p += d;  /* set real beginning of file and size */
  878.       ai->size -= d;
  879.       ai->arlen -= d;
  880.     }
  881.     else {  /* normal file name <= 16 chars */
  882.       char *n = &ah->ar_name[16];
  883.       int len;
  884.  
  885.       for (len=16; len>0; len--)
  886.         if (*(--n) != ' ')
  887.           break;
  888.       if (len && *n=='/')  /* GNU */
  889.         --len;
  890.       memcpy(ai->name,ah->ar_name,len);
  891.       ai->name[len] = 0;
  892.     }
  893.  
  894.     if (strncmp(ah->ar_fmag,ARFMAG,2))
  895.       error(42,ai->arname,ai->name);  /* consistency check failed */
  896.     ai->header = ah;
  897.     ai->data = p;
  898.     size = (ai->size&1) ? (ai->size+1) : ai->size;
  899.     ai->next = (struct ar_hdr *)(p + size);
  900.     if ((long)(ai->arlen -= size) < 0)
  901.       error(37,ai->arname,ai->name);  /* Malformatted archive member */
  902.   }
  903.   while (cont);
  904.   return (TRUE);
  905. }
  906.